

package ro.ase.catalog.security.filter;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.intercept.AbstractSecurityInterceptor;
import org.springframework.security.intercept.InterceptorStatusToken;
import org.springframework.security.intercept.ObjectDefinitionSource;
import org.springframework.security.intercept.method.MethodDefinitionSource;
import ro.ase.catalog.beans.Authority;
import ro.ase.catalog.security.service.ISecurityInterceptor;

import java.util.LinkedHashMap;
import java.util.List;


public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor {
    //~ Instance fields ================================================================================================

    private static MethodDefinitionSource objectDefinitionSource;
    private static final String AUTHORITY_TYPE = "METHOD";
    @Autowired
    private ISecurityInterceptor securityInterceptor;

    //~ Methods ========================================================================================================

    public MethodDefinitionSource getObjectDefinitionSource() {
        return objectDefinitionSource;
    }

    @SuppressWarnings("unchecked")
    public Class getSecureObjectClass() {
        return MethodInvocation.class;
    }

    /**
     * This method should be used to enforce security on a <code>MethodInvocation</code>.
     *
     * @param mi The method being invoked which requires a security decision
     *
     * @return The returned value from the method invocation
     *
     * @throws Throwable if any error occurs
     */
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object result = null;
        InterceptorStatusToken token = super.beforeInvocation(mi);

        try {
            result = mi.proceed();
        } finally {
            result = super.afterInvocation(token, result);
        }

        return result;
    }


    public ObjectDefinitionSource obtainObjectDefinitionSource() {
        if(objectDefinitionSource == null){
            AspectJMethodMatcher methodMatcher = new AspectJMethodMatcher();
            LinkedHashMap<String, ConfigAttributeDefinition> methodMap
                    = new LinkedHashMap<String, ConfigAttributeDefinition>();
            
            List<Authority> authorities = securityInterceptor.loadAuthorities(AUTHORITY_TYPE);
            methodMap = new LinkedHashMap<String, ConfigAttributeDefinition>();
            for (Authority authority : authorities) {
                String grantedAuthorities = authority.getRolesString();
                if (StringUtils.isNotEmpty(grantedAuthorities)) {
                    ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
                    configAttrEditor.setAsText(grantedAuthorities);
                    ConfigAttributeDefinition definition = (ConfigAttributeDefinition) configAttrEditor
                            .getValue();
                    methodMap.put(authority.getValue(), definition);
                }
            }
            objectDefinitionSource = new DefaultMethodDefinitionSource(methodMatcher, methodMap);
        }
        return objectDefinitionSource;
    }

    public static void refresh() {
        objectDefinitionSource = null;
    }
    
    public void setObjectDefinitionSource(MethodDefinitionSource newSource) {
        objectDefinitionSource = newSource;
    }
}
